%% coding: utf-8
-module(stack).
-compile(export_all).
% -export([start/0]).

% 一个小型计算器程序
% 用于演示函数式编程解决问题，程序重构
% 能否将一个一个操作，定义为一个原子，并组合到一起

% 定义一个类型，该句不会真正编译
-type stack()::{stack_contents, list(float())}.

% 定义一个函数类型，该句不会编译进去
-spec push(float(),stack()) -> stack().
% 函数的实现
push(N, {stack_contents, S}) ->
    {stack_contents, [N] ++ S}.

% 定义一个函数类型，该句不会编译进去
-spec pop(stack()) -> {float(),stack()}.
% 函数的实现
pop({stack_contents, [H|T]}) ->
    {H, {stack_contents, T}}.

% 定义One()
% one(S) -> push(1.0, S).
% two(S) -> push(2.0, S).
% three(S) -> push(3.0, S).

one() ->
    fun(S) ->
        push(1.0, S)
    end.
two() ->
    fun(S) ->
        push(2.0, S)
    end.
three() ->
    fun(S) ->
        push(3.0, S)
    end.

% 定义加和乘法
% add(S) ->
%     {A,S1} = pop(S),
%     {B,S2} = pop(S1),
%     Result = A+B,
%     push(Result,S2).

% mul(S) ->
%     {A,S1} = pop(S),
%     {B,S2} = pop(S1),
%     Result = A*B,
%     push(Result,S2).
% -spec binary(fun(float(),float()) -> float()), stack()
binary(Op,S) ->
    {N1,S1} = pop(S),
    {N2,S2} = pop(S1),
    Result = Op(N1,N2),
    push(Result,S2).

add() ->
    fun(S) ->
        binary(fun(X,Y) -> X+Y end, S)
    end.
mul() ->
    fun(S) ->
        binary(fun(X,Y) -> X*Y end, S)
    end.

show() ->
    fun(S) ->
        {Value, _S1} = pop(S),
        io:format("The Result is ~p~n", [Value]),
        S
    end.

empty() -> {stack_contents, []}.

% test9() ->
    % add(two(one(empty()))).
    % 函数之间是可以组合的，已经比一般语言要强了！
    % 太难用了，这括号个数谁受得了！

compose([]) ->
    fun(S) ->
        S
    end;
compose([Op|T]) ->
    fun(S) ->
        (compose(T))(Op(S))
    end.

test10() ->
    % Op = compose([fun one/1, fun two/1, fun add/1]),
    Op = compose([one(), two(), add(), show()]),
    Op(empty()).

